#include "eeprom.h"

unsigned char volatile spi_ready, curr_byte;
unsigned short xdata odometer_byte_ptr;
eeprom_ptr xdata ep;

unsigned char xdata spi_dont_care_bytes[4] = {0};

//we're using an ATMEL AT45DB161D 16mbit SPI eeprom
//this structure sets up the commands we need to send
//to read and write the 528 byte pages
/*
typedef struct{
	unsigned char op_code;
	unsigned short dont_care			: 2;
	unsigned short page_address		: 12;
	unsigned short byte_address_h	: 2;
	unsigned char byte_address_l	: 8;
		
} eeprom_ptr;

*/
void setup_code(unsigned char op, unsigned short page, unsigned short byte_offset){
	ep.op_code = op;
	ep.page_address = page;
	ep.byte_address_h = (unsigned char) ((byte_offset & 0x0300) >> 8);
	ep.byte_address_l = (unsigned char) (byte_offset & 0x00FF);
	ep.dont_care = 0;
}

//keep track of the page and byte offset for the gps log
void increment_gps_ptr(){
	gps_byte_ptr += (sizeof gl);
	if(gps_byte_ptr >= 528){
		gps_byte_ptr = 0;
		gps_page_ptr += 1;
	}
}

//find our odometer reading, and gps offset
//please note that we're going to wear out the odometer page in about 3 years of driving 20 miles per day
void init_eeprom(){

	unsigned long xdata temp;

	gps_byte_ptr = 0;
	gps_page_ptr = GPS_MIN_PAGE;

	//load our odometer reading
	setup_code(DIRECT_PAGE_READ, ODOMETER_PAGE, 0);
	EEPROM_SEL = 0;
	spi_write((unsigned char *)&ep, sizeof ep);
	//Four don't care bytes
	spi_write(spi_dont_care_bytes, sizeof spi_dont_care_bytes);
	temp = 0;
	spi_read((unsigned char*)&temp, sizeof temp);
	EEPROM_SEL = 1;
	
	if (temp == 0xFFFFFFFF){
		odometer = 0;
	}
	odometer = *((float *)&temp);
	
	//load the splash and custom characters
	setup_code(DIRECT_PAGE_READ, LCD_PAGE, 0);
	EEPROM_SEL = 0;
	spi_write((unsigned char *)&ep, sizeof ep);
	//Four don't care bytes
	spi_write(spi_dont_care_bytes, sizeof spi_dont_care_bytes);

	spi_read(splash, sizeof splash);
	spi_read(back_slash, sizeof back_slash);
	spi_read(degrees, sizeof degrees);

	EEPROM_SEL = 1;

	//find next open gps log spot
	gps_byte_ptr = 0;
	gps_page_ptr = GPS_MIN_PAGE;
	setup_code(CONTINUOUS_PAGE_READ, GPS_MIN_PAGE, 0);
	EEPROM_SEL = 0;
	spi_write((unsigned char *)&ep, sizeof ep);
	//spi_write(spi_dont_care_bytes, sizeof spi_dont_care_bytes);
	do{
		memset(&gl, 0, sizeof gl);
		spi_read((unsigned char*)&gl, sizeof gl);
		if(gl.header != GPS_LOG_HEADER)
			break;
		increment_gps_ptr();
	}while(gl.header == GPS_LOG_HEADER);
	gps_byte_ptr = 0;
	EEPROM_SEL = 1;
	
}

void save_gps_log(unsigned char force_write){
	//select buffer	2
	setup_code(WRITE_BUFFER_2, DONT_CARE, gps_byte_ptr);
	EEPROM_SEL = 0;
	spi_write((unsigned char *)&ep, sizeof ep);
	//write to buffer 2
	spi_write((unsigned char*)(&gl), sizeof gl); 
	EEPROM_SEL = 1;
	//check for a full buffer
	if(gps_byte_ptr == 528 - sizeof gl || force_write){
		setup_code(BUFFER_2_TO_PAGE, gps_page_ptr, 0);
		EEPROM_SEL = 0;
		//comit buffer to page
		spi_write((unsigned char *)&ep, sizeof ep);
		EEPROM_SEL = 1;
	}
	increment_gps_ptr();
	
}

void save_odometer(){
	//select buffer
	setup_code(WRITE_BUFFER_1, DONT_CARE, 0);
	EEPROM_SEL = 0;
	spi_write((unsigned char *)&ep, sizeof ep);
	//write to buffer
	spi_write((unsigned char*)(&odometer), sizeof odometer); 
	EEPROM_SEL = 1;
	setup_code(BUFFER_1_TO_PAGE, ODOMETER_PAGE, 0);
	EEPROM_SEL = 0;
	//comit buffer to page
	spi_write((unsigned char *)&ep, sizeof ep);
	EEPROM_SEL = 1;
}

//write len bytes from buf
void spi_write(unsigned char* buf, unsigned short len){
	unsigned char index = 0;
	while(index < len){
		spi_ready = 0;
		SPI0DAT = buf[index++];
		while(SPIBUSY());
		while(!spi_ready);
	}
}

//read len bytes into buf
void spi_read(unsigned char* buf, unsigned short len){
	unsigned char xdata index = 0;
	while(index < len){
		spi_ready = 0;
		SPI0DAT = 0x00;
		while(!spi_ready);
		buf[index++] = curr_byte;	
	}
}

void dump_gps(){
	unsigned char i;
	//gps_page_ptr = 0;
	//gps_byte_ptr = GPS_MIN_PAGE;
	setup_code(0x03, GPS_MIN_PAGE, 0);
	EEPROM_SEL = 0;
	spi_write((unsigned char *)&ep, sizeof ep);
	do{
		spi_read((unsigned char*)&gl, sizeof gl);
		if(gl.header != GPS_LOG_HEADER)
			break;
		//increment_gps_ptr();
		
		for(i = 0; i < sizeof gl; i++){
			xmitFlag = 0;
			SBUF0 = ((unsigned char *)&gl)[i];
			// Wait for TI0 to be set
			while (!xmitFlag);
		}
	}while(gl.header == GPS_LOG_HEADER);
	EEPROM_SEL = 1;
}

//handle the interrupt
void SPI_ISR() interrupt 6{
	curr_byte = SPI0DAT;
	SPIF = 0;
	spi_ready = 1;
}
